import os,json
import numpy as np
import cv2
from util.sketlonize import Sketlonize
# 可视化
class CornerDetector:
    def __init__(self, block_size=2, ksize=5, k=0.05):
        '''
        初始化方法，设置Harris角点检测的参数。
        参数:
            block_size (int): 计算角点检测中结构张量的邻域大小。
            ksize (int): Sobel导数滤波器核的大小。
            k (float): Harris角点检测的自由参数，通常在0.04到0.06之间。
        '''
        self.block_size = block_size
        self.ksize = ksize
        self.k = k
    
    def point_detector(self, img):
        '''
        检测图像中的角点。
        输入:
            img (array): 输入的灰度图像。
        输出:
            points (list of tuples): 检测到的角点坐标列表。
        '''
        # 将图像转换为灰度图像（如果需要）
        if len(img.shape) == 3:
            gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        else:
            gray = img
        
        # 将图像转换为float32格式
        gray = np.float32(gray)
        
        # 使用Harris角点检测
        dst = cv2.cornerHarris(gray, self.block_size, self.ksize, self.k)
        
        # 对检测结果进行阈值处理以获取角点
        dst = cv2.dilate(dst, None)  # 膨胀操作，便于可视化
        threshold = 0.01 * dst.max()
        points = np.argwhere(dst > threshold)
        points = [tuple(pt[::-1]) for pt in points]  # 变换为(x, y)坐标
        points = [[x,y] for x,y in points if img[y,x]>0]
        return points
    
    def visual_point(self, img, points, point_radius=1, save_path='output.png'):
        '''
        在图像上可视化角点。
        输入:
            img (array): 输入的图像。
            points (list of tuples): 角点坐标列表。
            point_radius (int): 角点的可视化半径。
            save_path (str): 保存带有可视化角点的图像路径。
        输出:
            None
        '''
        # 如果输入是灰度图像，将其转换为BGR以便可视化
        if len(img.shape) == 2:
            img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
        
        # 绘制角点
        for point in points:
            cv2.circle(img, point, point_radius, (255, 0, 0), -1)  # 蓝色点
        
        # 保存结果图像
        cv2.imwrite(save_path, img)
        print(f"Visualized image saved at {save_path}")
    def detect_bifurcation_points(self, img, points):
        '''
        检查给定的点是否是分叉点。
        输入:
            img (array): 输入的二值骨架图。
            points (list of tuples): Harris角点检测出的候选点。
        输出:
            bifurcation_points (list of tuples): 检测到的分叉点坐标列表。
        '''
        bifurcation_points = []
        rows, cols = img.shape
        
        # 遍历每个角点，检查其8邻域
        for x, y in points:
            if 1 <= x < cols - 1 and 1 <= y < rows - 1:  # 确保点在图像边界内
                neighborhood = img[y-1:y+2, x-1:x+2]  # 获取8邻域
                neighbor_points = [(i, j) for i in range(3) for j in range(3) if not (i == 1 and j == 1) and neighborhood[i, j] > 0]

                # 检查是否有三个不相邻的点
                if self.is_bifurcation(neighbor_points):
                    bifurcation_points.append((x, y))
        
        return bifurcation_points
    
    def is_bifurcation(self, neighbor_points):
        '''
        检查邻域中是否存在3个不相邻的点。
        输入:
            neighbor_points (list of tuples): 邻域中存在的点。
        输出:
            bool: 如果满足分叉点条件则返回True，否则返回False。
        '''
        num_points = len(neighbor_points)

        if num_points < 3:
            return False
        # 定义邻接关系，排除对角线的相邻点
        def is_adjacent(p1, p2):
            dy = abs(p1[0] - p2[0])
            dx = abs(p1[1] - p2[1])

            # 检查是否是上下或左右相邻
            return (dy == 0 and dx == 1) or (dy == 1 and dx == 0)

        # 检查非相邻点的分布
        non_adjacent_count = 0
        for i in range(num_points):
            p1 = neighbor_points[i]
            adjacent = False
            for j in range(i + 1, num_points):
                p2 = neighbor_points[j]
                if is_adjacent(p1, p2):  # 仅检查水平和垂直方向是否相邻
                    adjacent = True
                    break
            if not adjacent:
                non_adjacent_count += 1

        return non_adjacent_count >= 3

    def visual_bifurcation_points(self, img, points,  save_path='output.png'):
        '''
        在图像上可视化分叉点。
        输入:
            img (array): 输入的图像。
            points (list of tuples): 分叉点坐标列表。
            save_path (str): 保存带有可视化分叉点的图像路径。
        输出:
            None
        '''
        # 如果输入是灰度图像，将其转换为BGR以便可视化
        if len(img.shape) == 2:
            img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
        
        # 把point的位置的像素设置为红色
        for point in points:
            img[point[1], point[0]] = [0, 0, 255]  # 红色点
        if save_path is not None:
            # 保存结果图像
            cv2.imwrite(save_path, img)
            print(f"Visualized image saved at {save_path}")
        else:
            raise ValueError("save_path cannot be None")
if __name__ == '__main__':
    # 获取配置
    data_path='../Dataset/infantImages'
    # 读取数据字典
    with open(os.path.join(data_path, 'annotations.json'), 'r') as f:
        data_dict = json.load(f)
    visual_dir='./experiments/new_feature'
    if not os.path.exists(visual_dir):
        os.makedirs(visual_dir)
    data_set_path='./experiments/dataset'
    vascular_dir=os.path.join(data_set_path,'vascular')
    image_dir= os.path.join(vascular_dir,'images')
    image_name= '1243.jpg'
    vascular_path=os.path.join(vascular_dir,image_name)
    skeletoner=Sketlonize(0.35)
    skeleton,vascular_cnt_img,vascular_cnt=skeletoner.sketlonize(vascular_path,optic_disc_coor=data_dict[image_name]['optic_disc_pred']['position'], min_size=100)
    # 拐点检测
    corner_detector = CornerDetector()
    points = corner_detector.point_detector(skeleton)
    corner_detector.visual_point(skeleton, points, save_path=os.path.join(visual_dir,'harris.jpg'))

    # 检测分叉点
    bifurcation_points = corner_detector.detect_bifurcation_points(skeleton, points)
    corner_detector.visual_bifurcation_points(skeleton, bifurcation_points, save_path=os.path.join(visual_dir,'bifurcation.jpg'))
